package com.tanhua.server.service;


import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.JSON;
import com.tanhua.autoconfig.template.HuanXinTemplate;
import com.tanhua.commons.utils.Constants;
import com.tanhua.dubbo.api.*;
import com.tanhua.model.domain.Question;
import com.tanhua.model.domain.UserInfo;
import com.tanhua.model.dto.RecommendUserDto;
import com.tanhua.model.vo.NearUserVo;
import com.tanhua.model.mongo.RecommendUser;
import com.tanhua.model.mongo.Visitors;
import com.tanhua.model.vo.ErrorResult;
import com.tanhua.model.vo.PageResult;
import com.tanhua.model.vo.TodayBest;
import com.tanhua.server.exception.BusinessException;
import com.tanhua.server.interceptor.UserHolder;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.*;

@Service
public class TanhuaService {

    @DubboReference
    private RecommendUserApi recommendUserApi;

    @DubboReference
    private UserInfoApi userInfoApi;

    @DubboReference
    private QuestionApi questionApi;

    @Autowired
    private HuanXinTemplate huanXinTemplate;

    @Value("${tanhua.default.recommend.users}")
    private String users;

    @DubboReference
    private UserLikeApi userLikeApi;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired
    private MessagesService messagesService;

    @DubboReference
    private UserLocationApi userLocationApi;

    /**
     * 分页查询推荐列表
     *
     * @param dto
     * @return
     */
    public PageResult recommendation(RecommendUserDto dto) {
        //1.获取用户id
        Long userId = UserHolder.getUserId();
        //2、调用recommendUserApi分页查询数据列表（PageResult -- RecommendUser）
        PageResult pr = recommendUserApi.queryRecommendUserList(dto.getPage(), dto.getPagesize(), userId);
        //3、获取分页中的RecommendUser数据列表
        List<RecommendUser> items = (List<RecommendUser>) pr.getItems();
        //4、判断列表是否为空
        if (CollUtil.isEmpty(items)) {
            return pr;
        }
        //5、提取所有推荐的用户id列表
        //hutool工具获取所有推荐的用户id列表
        List<Long> ids = CollUtil.getFieldValues(items, "userId", Long.class);
        //构造UserInfo条件 传过来的有年龄和性别
        UserInfo userInfo = new UserInfo();
        userInfo.setAge(dto.getAge());
        userInfo.setGender(dto.getGender());
        //6、构建查询条件，批量查询所有的用户详情
        Map<Long, UserInfo> map = userInfoApi.findByIds(ids, userInfo);
        //7、循环推荐的数据列表，构建vo对象
        List<TodayBest> list = new ArrayList<>();
        //循环
        for (RecommendUser item : items) {
            //通过id获取UserInfo对象
            UserInfo info = map.get(item.getUserId());
            if (info != null) {
                //如果对象不等于空，调用init方法实现封装
                TodayBest vo = TodayBest.init(info, item);
                //把封装好的vo添加进去
                list.add(vo);
            }
        }
        //8、构造返回值
        pr.setItems(list);
        return pr;
    }

    /**
     * 今日佳人
     *
     * @return
     */
    public TodayBest todayBest() {
        //1.获取用户id
        Long userId = UserHolder.getUserId();
        //2、调用API查询
        RecommendUser recommendUser = recommendUserApi.queryWithMaxScore(userId);
        //判断 如果没有查到就新建一个
        if (recommendUser == null) {
            recommendUser = new RecommendUser();
            recommendUser.setUserId(1L);
            recommendUser.setScore(99d);
        }
        //3、将RecommendUser转化为TodayBest对象
        UserInfo userInfo = userInfoApi.findById(recommendUser.getUserId());
        TodayBest vo = TodayBest.init(userInfo, recommendUser);
        return vo;
    }


    @DubboReference
    private VisitorsApi visitorsApi;

    /**
     * 佳人信息
     *
     * @param userId
     * @return
     */
    public TodayBest personalInfo(Long userId) {
        //1.根据id查询用户信息
        UserInfo userInfo = userInfoApi.findById(userId);
        //2.根据操作人id和查看的用户id，查看两者的推荐数据
        RecommendUser user = recommendUserApi.personalInfo(userId, UserHolder.getUserId());
        //构造visitors对象
        Visitors visitors = new Visitors();
        visitors.setUserId(userId);
        visitors.setVisitorUserId(UserHolder.getUserId());
        visitors.setFrom("首页");
        visitors.setDate(System.currentTimeMillis());
        visitors.setScore(user.getScore());
        visitors.setVisitDate(new SimpleDateFormat("yyyyMMdd").format(new Date()));
        //调用api保存
        visitorsApi.save(visitors);
        //3.构造返回值
        return TodayBest.init(userInfo, user);
    }

    /**
     * 查看陌生人问题
     *
     * @param userId
     * @return
     */
    public String strangerQuestions(Long userId) {
        //1.通过id查询Questions对象
        Question question = questionApi.findById(userId);
        //2.返回陌生人问题内容，没有就创建一个默认的
        return question == null ? "你喜欢大海吗" : question.getTxt();
    }

    /**
     * 回复陌生人问题
     *
     * @param userId
     * @param reply
     */
    public void stranger(Long userId, String reply) {
        //1.构造数据
        Long id = UserHolder.getUserId();
        //通过id获取用户详情
        UserInfo userInfo = userInfoApi.findById(id);
        //获取用户昵称
        String nickname = userInfo.getNickname();
        Map map = new HashMap();
        //发送人的id
        map.put("userId", id);
        //发送人的环信id
        map.put("hanXinId", Constants.HX_USER_PREFIX + id);
        //发送人的昵称
        map.put("nickname", nickname);
        //陌生人问题
        map.put("strangerQuestion", strangerQuestions(userId));
        //回复的内容
        map.put("reply", reply);
        //把map转为JSON字符串
        String jsonString = JSON.toJSONString(map);
        //2.调用huanXinTemplate发送信息
        Boolean aBoolean = huanXinTemplate.sendMsg(Constants.HX_USER_PREFIX + id, jsonString);
        //如果发送失败抛出一个异常
        if (!aBoolean) {
            throw new BusinessException(ErrorResult.error());
        }
    }

    /**
     * 左滑右滑
     *
     * @return
     */
    public List<TodayBest> cards() {
        //1.调用api查询数据列表（排除喜欢和不喜欢的数据，定义数量）
        List<RecommendUser> recommend = recommendUserApi.queryCardsList(UserHolder.getUserId(), 10);
        //2.判断数据是否存在
        if (CollUtil.isEmpty(recommend)) {
            //不存在就构造默认的数据
            recommend = new ArrayList<>();
            String[] split = users.split(",");
            for (String s : split) {
                RecommendUser recommendUser = new RecommendUser();
                //String转成Long型
                recommendUser.setUserId(Convert.toLong(s));
                recommendUser.setToUserId(UserHolder.getUserId());
                recommendUser.setScore((RandomUtil.randomDouble(60, 90)));
                recommend.add(recommendUser);
            }
        }
        //3.构造vo
        //通过recommend获取每一个推荐的用户id
        List<Long> longs = CollUtil.getFieldValues(recommend, "userId", Long.class);
        //调用userInfo查询用户详情
        Map<Long, UserInfo> infoMap = userInfoApi.findByIds(longs, null);
        List<TodayBest> vos = new ArrayList<>();
        for (RecommendUser recommendUser : recommend) {
            UserInfo userInfo = infoMap.get(recommendUser.getUserId());
            if (userInfo != null) {
                TodayBest vo = TodayBest.init(userInfo, recommendUser);
                vos.add(vo);
            }
        }
        return vos;
    }

    /**
     * 喜欢
     *
     * @param likeUserId
     * @return
     */
    public void likeUser(Long likeUserId) {
        //1.调用api保存喜欢数据
        Boolean aBoolean = userLikeApi.saveOrUpdate(UserHolder.getUserId(), likeUserId, true);
        //2.保存失败抛出异常
        if (!aBoolean) {
            throw new BusinessException(ErrorResult.error());
        }
        //3.删除redis中不喜欢的标记
        redisTemplate.opsForSet().remove(Constants.USER_NOT_LIKE_KEY + UserHolder.getUserId(), likeUserId.toString());
        //4.保存喜欢的标记到redis中
        redisTemplate.opsForSet().add(Constants.USER_LIKE_KEY + UserHolder.getUserId(), likeUserId.toString());
        //5.判断是否是双向喜欢
        //拼装被喜欢人的key，通过他的key来redis获取value为自己的数据
        String key = Constants.USER_LIKE_KEY + likeUserId;
        Boolean member = redisTemplate.opsForSet().isMember(key, UserHolder.getUserId().toString());
        //6.如果双向喜欢就加为好友
        if (member) {
            //调用添加好友的方法
            messagesService.contacts(likeUserId);
        }
    }

    /**
     * 不喜欢
     *
     * @param likeUserId
     */
    public void unlikeUser(Long likeUserId) {
        //1.调用api保存数据到数据库
        Boolean aBoolean = userLikeApi.saveOrUpdate(UserHolder.getUserId(), likeUserId, false);
        //2.保存失败抛出异常
        if (!aBoolean) {
            throw new BusinessException(ErrorResult.error());
        }
        //3.删除redis中喜欢的标记数据
        redisTemplate.opsForSet().remove(Constants.USER_LIKE_KEY + UserHolder.getUserId(), likeUserId.toString());
        //4.保存不喜欢的标记到redis中
        redisTemplate.opsForSet().add(Constants.USER_NOT_LIKE_KEY + UserHolder.getUserId(), likeUserId.toString());

    }

    /**
     * 搜附近
     *
     * @param gender   性别
     * @param distance 距离
     * @return
     */
    public List<NearUserVo> search(String gender, String distance) {
        //1.调用api查询附近的用户（返回的是附近的人的所有用户id，也包含当前用户的id）
        List<Long> list = userLocationApi.queryNearUser(UserHolder.getUserId(), Double.valueOf(distance));
        //2.判断集合是否为空
        if (CollUtil.isEmpty(list)) {
            //为空返回一个空的集合
            return new ArrayList<>();
        }
        //3.获取所有附近人的用户信息，不包括自己，设置性别需求
        UserInfo userInfo = new UserInfo();
        userInfo.setGender(gender);
        Map<Long, UserInfo> infoMap = userInfoApi.findByIds(list, userInfo);
        //4.封装vo并返回
        List<NearUserVo> vos = new ArrayList<>();
        for (Long aLong : list) {
            //排除当前用户自己
            if (aLong.equals(UserHolder.getUserId())) {
                continue;
            }
            UserInfo info = infoMap.get(aLong);
            if (info != null) {
                NearUserVo vo = NearUserVo.init(info);
                vos.add(vo);
            }
        }
        return vos;
    }
}
